package com.ljx.funchat.chat.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Pair;
import com.ljx.funchat.chat.dao.ContactDao;
import com.ljx.funchat.chat.dao.MessageDao;
import com.ljx.funchat.chat.domain.dto.RoomBaseInfo;
import com.ljx.funchat.chat.domain.entity.*;
import com.ljx.funchat.chat.domain.enums.RoomTypeEnum;
import com.ljx.funchat.chat.domain.vo.resp.ChatRoomResp;
import com.ljx.funchat.chat.service.IContactService;
import com.ljx.funchat.chat.service.adapter.ContactAdapter;
import com.ljx.funchat.chat.service.cache.RoomCache;
import com.ljx.funchat.chat.service.cache.RoomFriendCache;
import com.ljx.funchat.chat.service.cache.RoomGroupCache;
import com.ljx.funchat.common.domain.vo.req.CursorPageBaseReq;
import com.ljx.funchat.common.domain.vo.resp.CursorPageBaseResp;
import com.ljx.funchat.user.dao.UserDao;
import com.ljx.funchat.user.domain.entity.User;
import com.ljx.funchat.user.service.cache.UserCache;
import com.ljx.funchat.user.service.cache.UserInfoCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ContactServiceImpl implements IContactService {

    @Autowired
    private ContactDao contactDao;

    @Autowired
    private RoomCache roomCache;

    @Autowired
    private RoomGroupCache roomGroupCache;

    @Autowired
    private RoomFriendCache roomFriendCache;

    @Autowired
    private UserInfoCache userInfoCache;

    @Autowired
    private MessageDao messageDao;

    @Override
    public CursorPageBaseResp<ChatRoomResp> getContactPage(Long uid, CursorPageBaseReq request) {
        // 用户基础会话
        CursorPageBaseResp<Contact> contactPage = contactDao.getContactPage(uid, request);
        List<Long> baseRoomIds = contactPage.getList().stream().map(Contact::getRoomId).collect(Collectors.toList());
        CursorPageBaseResp<Long> initPage = CursorPageBaseResp.init(contactPage, baseRoomIds);
        // 获取房间具体信息【头像，未读数，名称】并返回
        List<ChatRoomResp> res = buildChatRoomResp(uid, initPage);
        return CursorPageBaseResp.init(contactPage, res);
    }

    private List<ChatRoomResp> buildChatRoomResp(Long uid, CursorPageBaseResp<Long> initPage) {
        // 获取房间列表缓存
        Map<Long, Room> roomMap = roomCache.getBatch(initPage.getList());
        // 根据单/群聊进行分类
        Map<Integer, List<Long>> typeMap = roomMap.values().stream().collect(Collectors.groupingBy(Room::getType,
                Collectors.mapping(Room::getId, Collectors.toList())));
        // 获取群聊具体信息
        List<Long> groupRoomIds = typeMap.get(RoomTypeEnum.GROUP.getType());
        Map<Long, RoomGroup> groupRoomMap = roomGroupCache.getBatch(groupRoomIds);
        // 获取好友信息
        List<Long> friendRoomIds = typeMap.get(RoomTypeEnum.FRIEND.getType());
        Map<Long, RoomFriend> friendRoomMap = roomFriendCache.getBatch(friendRoomIds);
        Set<Long> friendIds = getFriendUidSet(friendRoomMap, uid);
        Map<Long, User> userMap = userInfoCache.getBatch(new ArrayList<>(friendIds));
        // 组合群聊和好友的房间
        Map<Long, RoomBaseInfo> roomBaseInfoMap = ContactAdapter.buildRoomBaseInfo(roomMap, groupRoomMap, userMap, friendRoomMap, uid);
        // 获取消息未读数
        List<Long> lastMsgIds = roomMap.values().stream().map(Room::getLastMsgId).collect(Collectors.toList());
        List<Message> messages = messageDao.listByIds(lastMsgIds);
        Map<Long, Message> msgMap = messages.stream().collect(Collectors.toMap(Message::getId, Function.identity()));
        Map<Long, Integer> unReadCountMap = getUnReadCountMap(uid, initPage.getList());
        // 返回结果
        return roomMap.values().stream().map(item -> {
            RoomBaseInfo roomBaseInfo = roomBaseInfoMap.get(item.getId());
            ChatRoomResp chatRoomResp = BeanUtil.copyProperties(roomBaseInfo, ChatRoomResp.class);
            Message message = msgMap.get(roomBaseInfo.getLastMsgId());
            chatRoomResp.setText(message.getContent());
            chatRoomResp.setUnreadCount(unReadCountMap.get(item.getId()));
            return chatRoomResp;
        }).collect(Collectors.toList());
    }

    /**
     * 获取消息未读数Map
     * @param uid
     * @param roomIds
     * @return
     */
    private Map<Long, Integer> getUnReadCountMap(Long uid, List<Long> roomIds) {
        if (Objects.isNull(uid)) {
            return new HashMap<>();
        }
        List<Contact> contacts = contactDao.getByRoomIds(roomIds, uid);
        return contacts.parallelStream()
                .map(contact -> Pair.of(contact.getRoomId(), messageDao.getUnReadCount(contact.getRoomId(), contact.getReadTime())))
                .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
    }

    /**
     * 获取用户好友Id列表
     * @param friendRoomMap
     * @param uid
     * @return
     */
    private Set<Long> getFriendUidSet(Map<Long, RoomFriend> friendRoomMap, Long uid) {
        return friendRoomMap.values().stream()
                .map(item -> uid.equals(item.getUid1()) ? item.getUid2() : item.getUid1())
                .collect(Collectors.toSet());
    }

    @Override
    public void deleteContact(List<Long> ids, Long roomId) {
        contactDao.deleteContact(ids, roomId);
    }
}
